#include <iostream>
using namespace std;

const int N = 100010;
int n, m;

class heap
{
private:
    int h[N];
    int ph[N];
    int hp[N];
    int size;
    //因为堆的某个位置存的元素的大小是一定的，既h[1]是堆顶，x的左儿子是2x, 右儿子是2x + 1，而且x一定比左儿子或者右儿子都大或者都小
    //ph[k]是记录第k个输入的元素在h中的下标
    //hp[x]是指h[x]是第几个被插入的
    //size是指堆的大小
public:
    heap(int n);
    void up(int u);
    void down(int u);
    void h_swap(int a, int b);
    int pop();
};

heap::heap(int n)
{
    size = n;
    for (int i = 1; i <= n; ++i)
    {
        cin >> h[i];
        hp[i] = i;
        ph[i] = i;
    } //刚输入的时候都是全部按照输入顺序排列的
    //然后下面进行堆化
    //这里用size/2，是因为要从第一个不是最后一个叶子结点(也就是h[size])的父节点开始进行down操作
    //而由于子节点除以二一定等于父节点，所以这里用size/2
    for (int i = size / 2; i; --i)
        down(i);
}

void heap::h_swap(int a, int b) //这里的a和b的意思是在数组h中的索引
{
    swap(ph[hp[a]], ph[hp[b]]);
    swap(hp[a], hp[b]);
    swap(h[a], h[b]);
    return;
}

void heap::up(int u)
{
    /*
    while(u/2&&h[u/2]>h[u])
    {
        h_swap(u/2,u);
        u>>=1;
    }
    return;
    */
    //以上为迭代法
    //以下为递归法
    int t = u;
    if (u / 2 && h[u / 2] > h[t])
        t = u / 2;
    if (u != t)
    {
        h_swap(u, t);
        up(t);
    }
    return;
}

void heap::down(int u)
{
    int t = u;
    if (2 * u <= size && h[2 * u] < h[t])
        t = u * 2;
    if (2 * u + 1 <= size && h[2 * u + 1] < h[t])
        t = u * 2 + 1;
    if (u != t)
    {
        h_swap(u, t);
        down(t);
    }
    return;
}

int heap::pop()
{
    int min = h[1];
    h[1] = h[size];
    size--;
    down(1);
    return min;
}

int main()
{
    cin >> n >> m;
    heap H(n);
    while (m--)
        cout << H.pop() << " ";
    return 0;
}